#
#	coding:utf-8
#
# 语法的描述规则如下
# 成员名称, 位宽
#   [
#       ['name1', width]
#       ['name2', width]
#   ]

EN_DEBUG=True

I_NAME=0
I_WIDTH=1
I_ARRAY=2

MAX_BYTE=4

class b2v:
    def __init__(self, dtable=[]):
        self._dtable = dtable
        self._shift = 0
        for item in dtable:
            self.__setattr__(item[I_NAME], 0)

    def get_bits(self, paddr, width, roffset=0):
        """
         @param  paddr 源列表
         @param width 数据宽度
         @param roffset 原始偏移量
        """
        index = (roffset // 8)
        offset = (roffset % 8)
        data = 0

        # 根据初始偏移量和总宽度，计算需要拼接的最大字节
        max_offset = (width+offset+7)//8

        # 先左移offset偏移量
        for i in range(max_offset):
            data = (data<<8) + ((paddr[index+i] << offset) & 0xffff)
            if (i==0):
                data = data & 0xff
            if EN_DEBUG: print("%d %0x"%(i, data))
        # 最后根据总移位的位数，减去width对应应保留的位数，得到需要额外移位的位数
        rest_s = max_offset*8 - (width+7//8*8)
        data = data>>rest_s
        if EN_DEBUG: print("%d %d %0x"%(5, rest_s, data))
        return data

    def make_bits(self, paddr, roffset, data, width):
        """
         @param paddr 源列表
         @param roffset 原始偏移量
         @param data 数据
         @param width 数据宽度         
        """
        index = (roffset // 8)
        offset = (roffset % 8)
        woffset = width%8

        # 若roffset不对齐，第一个字节需要与已有的字节拼
        max_offset = (width+offset+7)//8

        if offset == 0:
            raw = 0
        else:
            raw = paddr[index]

        # 8-width%8 表示将数据向左对齐
        data = data << (8 - woffset)%8
        data = data << (8 - offset)%8
        if (8 - woffset)%8 + (8 - offset)%8 >= 8:
            data = data >> 8
        
        extra_data = [0]*max_offset

        if EN_DEBUG: print("%X %s"%(data, extra_data))

        for i in range(max_offset):
            extra_data[max_offset-1-i] = (data&0x00ff)
            data = data >> 8

        if EN_DEBUG: print(extra_data)

        for i in range(max_offset):
            if i==0:
                paddr[index] = raw + extra_data[i]
            else:
                paddr[index+i] = extra_data[i]

        return paddr[index:index+max_offset]


    def stream_to_var(self, buff, table=None):
        shift = 0
        table = table or self._dtable
        for item in table:
            self.__setattr__(item[I_NAME], self.get_bits(buff, item[I_WIDTH], shift))
            shift = shift + item[I_WIDTH]

    def var_to_stream(self, dst, table=None):
        shift = 0
        table = table or self._dtable
        for item in table:
            self.make_bits(dst, shift, self.__getattribute__(item[I_NAME]), item[I_WIDTH])
            shift = shift + item[I_WIDTH] 

    def get_bytes(self, paddr, count, offset):
        """
         @param paddr 源列表
         @param offset 原始偏移量, 单位字节
         @param count 数据数量，单位字节     
        """
        data = 0
        for i in range(count):
            data = data << 8
            data = data + paddr[offset + i]
        return data
    
    def make_bytes(self, paddr, offset, data, count):
        """
         @param paddr 源列表
         @param offset 原始偏移量, 单位字节
         @param data 数据
         @param width 数据宽度，单位字节     
        """
        for i in range(count):
            paddr[offset + count-1-i] = (data&0x00ff)
            data = data >> 8
        return paddr

    def bytes_to_var(self, buff, table=None):
        shift = 0
        table = table or self._dtable
        for item in table:
            self.__setattr__(item[I_NAME], self.get_bytes(buff, item[I_WIDTH], shift))
            shift = shift + item[I_WIDTH]

    def var_to_bytes(self, dst, table=None):
        shift = 0
        table = table or self._dtable
        for item in table:
            self.set_bytes(dst, shift, self.__getattribute__(item[I_NAME]), item[I_WIDTH])
            shift = shift + item[I_WIDTH] 
